/*
 *  domain.cpp
 *  T3nsors2
 *
 *  Created by Michael Barriault on 10-06-16.
 *  Copyright 2010 University of Guelph. All rights reserved.
 *
 */

#include "domain.h"
#include "others.h"
#include <cstdlib>
#include <cstdarg>
#include <iostream>
#include "macros.h"

namespace t3 {

	domain::domain(void) {
		return;
	}
	
	domain::~domain(void) {
		print("Deleting domain");
		O->clear();
		r->clear();
		delete O;
		delete r;
	}
	
	int domain::at(int A) {
		return O->at(A);
	}
	
	int domain::size(void) {
		int T = 1;
		FOR(i,N) T*= at(i);
		return T;
	}
	
	int domain::upto(int A) {
		if ( A == -1 ) return 1;
		int T = at(A);
		for ( int i=A-1; i>=0; i-- ) T*=at(i);
		return T;
	}
	
	domain* domain::init(int l,...) {
		va_list vl;
		va_start(vl,l);
		int c = l;
		domain* D;
		try {
			D = new domain;
			D->O = new std::vector<int>(c,0);
			D->r = new std::vector<double>(2*c,0.);
		}
		catch (...) {
			Alloc_Error("Domain");
			throw;
		}
		D->N = c;
		D->O->at(0) = va_arg(vl,int)+1;
		FOR(i,c) {
			D->r->at(2*i) = va_arg(vl,double);
			D->r->at(2*i+1) = va_arg(vl,double);
		}
		FOR(i,c-1)
			D->O->at(i+1) = (D->O->at(0)-1) * ( D->r->at(2*i+3)-D->r->at(2*i+2) ) / ( D->r->at(1)-D->r->at(0) )+1;
		va_end(vl);
		D->count = 1;
		print("Making new domain");
		return D;
	}
	
	double& domain::min(int a) {
		return this->r->at(2*a);
	}

	double& domain::max(int a) {
		return this->r->at(2*a+1);
	}
	
	double domain::d(int a) {
		return (this->max(a)-this->min(a))/(this->at(a)-1);
	}
	
	domain* domain::retain(void) {
		print((string)"Domain going from " + itos(count) + " to ", true);
		count++;
		print(itos(count));
		return this;
	}

	void domain::release(void) {
		print((string)"Domain going from " + itos(count) + " to ", true);
		count--;
		print(itos(count));
		if ( count <= 0 ) delete this;
	}
	
	void check(t3::domain* O1, t3::domain* O2) {
		t3::check(O1->N, O2->N);
		t3::check(O1->size(), O2->size());
		FOR(n,O1->N) t3::check(O1->at(n), O2->at(n));
	}
	
	void check(int m, int n) {
		if ( n != m ) exit(2);
	}
	
}

